﻿using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace CustomVirtualizingPanel
{
    public class ItemContainerGeneratorDemoPanel : VirtualizingPanel
    {
        protected override Size ArrangeOverride(Size finalSize)
        {
            // 注意，在第一次使用 ItemContainerGenerator之前要先访问一下InternalChildren, 
            // 否则ItemContainerGenerator为null，是一个Bug
            UIElementCollection children = InternalChildren;

            ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
            for (int childIndex = 0; childIndex < children.Count; childIndex++)
            {
                var child = children[childIndex];

                // 通过数据
                var itemIndex = itemsControl.Items.IndexOf(((FrameworkElement)child).DataContext);
                if (itemIndex > -1)
                {
                    // 安排子元素布局
                    child.Arrange(new Rect(50 * itemIndex, 0, 50, 50));
                }
                else
                {
                    RemoveInternalChildRange(childIndex, 1);    // 移除子元素UI容器
                }
            }

            return base.ArrangeOverride(finalSize);
        }

        /// <summary>
        /// 实例化子元素
        /// </summary>
        /// <param name="itemIndex">数据条目索引</param>
        public void RealizeChild(int itemIndex)
        {
            IItemContainerGenerator generator = this.ItemContainerGenerator;
            GeneratorPosition position = generator.GeneratorPositionFromIndex(itemIndex);

            using (generator.StartAt(position, GeneratorDirection.Forward, allowStartAtRealizedItem: true))
            {
                bool isNewlyRealized;
                var child = (UIElement)generator.GenerateNext(out isNewlyRealized); // 实例化(构造出空的子元素UI容器)

                if (isNewlyRealized)
                {
                    AddInternalChild(child);
                    generator.PrepareItemContainer(child); // 填充UI容器数据

                    InvalidateArrange();
                }
                else
                {
                    MessageBox.Show("第" + (itemIndex + 1) + "个元素已经被实例化了");
                }
            }
        }

        /// <summary>
        /// 虚拟化子元素
        /// </summary>
        /// <param name="itemIndex">数据条目索引</param>
        public void VirtualizeChild(int itemIndex)
        {
            IItemContainerGenerator generator = this.ItemContainerGenerator;
            var childGeneratorPos = generator.GeneratorPositionFromIndex(itemIndex);
            if (childGeneratorPos.Offset == 0)
            {
                generator.Remove(childGeneratorPos, 1); // 虚拟化(从子元素UI容器中清除数据)

                InvalidateArrange();
            }
            else
            {
                MessageBox.Show("第" + (itemIndex + 1) + "个元素没有被实例化");
            }
        }

        /// <summary>
        /// 显示数据GeneratorPosition信息
        /// </summary>
        /// <returns></returns>
        public string DumpGeneratorContent()
        {
            IItemContainerGenerator generator = this.ItemContainerGenerator;
            ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);

            var log = new StringBuilder();
            string consoleInfo = "Generator positions:";
            Console.WriteLine(consoleInfo);
            log.AppendLine(consoleInfo);
            for (int i = 0; i < itemsControl.Items.Count; i++)
            {
                GeneratorPosition position = generator.GeneratorPositionFromIndex(i);

                consoleInfo = "Item index=" + i + ", Generator position: index=" + position.Index + ", offset=" + position.Offset;
                Console.WriteLine(consoleInfo);
                log.AppendLine(consoleInfo);
            }
            Console.WriteLine();
            log.AppendLine("");

            return log.ToString();
        }
    }
}
